MODULE IsoFilt;

(*$R-,S-,J+*)
(* Purpose of module: Change MIME text encoding to Atari special characters
 *)
(*$E MTP *)
FROM SYSTEM IMPORT BYTE;
IMPORT GEMDOSIO, InOut;


IMPORT FileNames, Strings, StrConv, WildCards;

IMPORT mtCommand, mtTextfiles, MagicStrings, MagicSys, MagicDOS;

TYPE tTranslationTable = ARRAY [128..255] OF BYTE;

/* Conversion table from `latin1' charset to `atarist' charset.
   Generated mechanically by GNU recode 3.4.

   The recoding should be reversible.
*/

unsigned char const latin1_to_atarist[256] =
  {
      0,   1,   2,   3,   4,   5,   6,   7, /*   0 -   7 */
      8,   9,  10,  11,  12,  13,  14,  15, /*   8 -  15 */
     16,  17,  18,  19,  20,  21,  22,  23, /*  16 -  23 */
     24,  25,  26,  27,  28,  29,  30,  31, /*  24 -  31 */
     32,  33,  34,  35,  36,  37,  38,  39, /*  32 -  39 */
     40,  41,  42,  43,  44,  45,  46,  47, /*  40 -  47 */
     48,  49,  50,  51,  52,  53,  54,  55, /*  48 -  55 */
     56,  57,  58,  59,  60,  61,  62,  63, /*  56 -  63 */
     64,  65,  66,  67,  68,  69,  70,  71, /*  64 -  71 */
     72,  73,  74,  75,  76,  77,  78,  79, /*  72 -  79 */
     80,  81,  82,  83,  84,  85,  86,  87, /*  80 -  87 */
     88,  89,  90,  91,  92,  93,  94,  95, /*  88 -  95 */
     96,  97,  98,  99, 100, 101, 102, 103, /*  96 - 103 */
    104, 105, 106, 107, 108, 109, 110, 111, /* 104 - 111 */
    112, 113, 114, 115, 116, 117, 118, 119, /* 112 - 119 */
    120, 121, 122, 123, 124, 125, 126, 127, /* 120 - 127 */
    199, 252, 233, 226, 228, 224, 229, 231, /* 128 - 135 */
    234, 235, 232, 239, 238, 236, 196, 197, /* 136 - 143 */
    201, 230, 198, 244, 247, 242, 251, 249, /* 144 - 151 */
    187, 214, 220, 243, 195, 209, 223, 159, /* 152 - 159 */
    225, 173, 155, 156, 245, 157, 192, 221, /* 160 - 167 */
    185, 189, 166, 174, 170, 237, 190, 255, /* 168 - 175 */
    248, 241, 253, 254, 186, 230, 188, 249, /* 176 - 183 */
    213, 191, 167, 175, 172, 171, 169, 168, /* 184 - 191 */
    182, 193, 194, 183, 142, 143, 146, 128, /* 192 - 199 */
    200, 144, 202, 203, 204, 205, 206, 207, /* 200 - 207 */
    208, 165, 210, 211, 212, 184, 153, 215, /* 208 - 215 */
    178, 217, 218, 219, 154, 180, 222, 158, /* 216 - 223 */
    133, 160, 131, 176, 132, 134, 145, 135, /* 224 - 231 */
    138, 130, 136, 137, 141, 161, 140, 139, /* 232 - 239 */
    240, 164, 149, 162, 147, 177, 148, 246, /* 240 - 247 */
    179, 151, 163, 150, 129, 216, 248, 152, /* 248 - 255 */
  };

CONST isoTable =  tTranslationTable {
       128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
       144,145,146,147,148,149,150,151,152,153,154,155,156,157,225,159,
        32,173,155,156,120,157,124,221, 34, 67,166,174,170, 45, 82,223,
       248,241,253,252, 39,230,227,249, 44, 49,167,175,172,171, 47,168,
       133,160,131, 65,142,143,146,128,138,144,136,137,141,161,140,139,
        68,165,149,162,147,111,153,120,237,151,163,150,154,121, 80,225,
       133,160,131, 97,132,134,145,135,138,130,136,137,141,161,140,139,
       100,164,149,162,147,111,148,246,237,151,163,150,129,121,112,152};


TYPE

  ASCII  = SET OF [0C..377C];

CONST

  HexDigits= ASCII {'0'..'9','A'..'F'};(* Alle hexadez. Ziffern *)

VAR inOpen,
    outOpen : BOOLEAN;
    in,
    out     : mtTextfiles.TEXTFILE;
    charsChanged,
    headLinesChanged : LONGCARD;

PROCEDURE CloseIt ();
BEGIN
  IF inOpen THEN mtTextfiles.CloseTextfile (in) END;
  IF outOpen THEN mtTextfiles.CloseTextfile (out) END;
END CloseIt;

PROCEDURE error (REF s : ARRAY OF CHAR);
BEGIN
  InOut.WriteString ("isofilt: ");
  InOut.WriteString (s);
  InOut.WriteLn;
  CloseIt();
  MagicSys.Terminate (1);
END error;

PROCEDURE Usage ();
  VAR str: Strings.String;
BEGIN
  InOut.WriteString ("Usage: ");
  IF mtCommand.ArgV()
  THEN
    mtCommand.ParamString (0, str);
    InOut.WriteString (str);
  ELSE
    InOut.WriteString ("isofilt");
  END;
  InOut.WriteString (" inputfile outputfile");
  InOut.WriteLn;
  CloseIt();
  MagicSys.Terminate (2);
END Usage;

PROCEDURE GetChar (val: INTEGER; VAR ch: ARRAY OF CHAR);
BEGIN
  IF val > 127
  THEN
    ch[0] := CHAR(isoTable[val]);
  ELSE
    ch[0] := CHR(val);
  END;
  IF HIGH(ch) > 0
  THEN
    ch[1] := 0C;
  END;
END GetChar;

PROCEDURE CheckId (VAR line: ARRAY OF CHAR): BOOLEAN;
BEGIN
  (* Gibt zur�ck, ob es sich um eine normale Nachricht oder um einen 
   * Kontrollblock (Infofile etc.) handelt.
   *)
  RETURN Strings.Pos ('@', line, 1) > 0;
END CheckId; 

PROCEDURE CheckTextLine (VAR line: ARRAY OF CHAR);
  VAR p, p2 : INTEGER;
      num   : ARRAY [0..3] OF CHAR;
      succ  : BOOLEAN;
      val   : INTEGER;
      start : CARDINAL;
BEGIN
  p := -1;
  REPEAT
    p := Strings.Pos ("=", line, p+1);
    IF p >= 0
    THEN
      Strings.Copy (line, p+1, 2, num, succ);
      IF (num[0] IN HexDigits) & (num[1] IN HexDigits)
      THEN
        Strings.Insert ("$", 0, num, succ);
        start := 0;
        val := StrConv.StrToInt (num, start, succ);
        IF succ & (val >= 32)
        THEN
          Strings.Delete (line, p, 3, succ);
          GetChar (val, num);
          Strings.Insert (num, p, line, succ);
          INC (charsChanged);
        END;
      END;
    END;
  UNTIL p < 0;
END CheckTextLine;

PROCEDURE CheckHeadLine (VAR line: ARRAY OF CHAR);
  VAR charSet : Strings.String;
      succ    : BOOLEAN;
      p, p2   : INTEGER;
BEGIN
  IF WildCards.NameMatching (line, "*=\?[iI]*\?=")
  THEN
    (* Enth„lt =?irgendwas?=, also wahrscheinlich ISO-Umlaute *)
    p := Strings.Pos ("=?", line, 1);
    IF p < 0 THEN RETURN END;
    (* Zwischen dem ersten Fragezeichen und dem zweiten steht der Name des
     * Zeichensatzes, extrahieren wir mal, werten wir aber noch nicht weiter aus
     *)
    p2 := Strings.Pos ("?", line, p+2);
    IF p2 < 0 THEN RETURN END;
    IF (line[p2+1] # 'Q') OR (line[p2+2] # '?') THEN RETURN END;
    Strings.Copy (line, p+2, p2-p-2, charSet, succ);
    Strings.Delete (line, p, p2-p+3, succ);
    (* Jetzt noch ?= am Ende suchen und entfernen *)
    p2 := Strings.Pos ("?=", line, p+1);
    IF p2 < 0 THEN RETURN END;
    Strings.Delete (line, p2, 2, succ);
    (* Und jetzt noch alle anderen Zeichen wandeln *)
    INC (headLinesChanged);
    CheckTextLine (line);
  END;
END CheckHeadLine;

VAR outf,
    tmpf : ARRAY [0..255] OF CHAR;
    line : ARRAY [0..32766] OF CHAR; 
    inNormalMessage: BOOLEAN;
BEGIN
  inOpen:= FALSE;
  outOpen := FALSE;
  charsChanged := 0;
  headLinesChanged := 0;
  IF mtCommand.ParamCount() # 1
  THEN
    Usage();
  END;
  mtCommand.ParamString (1, outf);
  (* tempor„ren Namen basteln *)
  FileNames.ConcatName (outf, ".TMP", tmpf);
  IF ~mtTextfiles.OpenTextfile (outf, mtTextfiles.READ, 32000, in)
  THEN
    error ("Kann Eingabedatei nicht ”ffnen!");
  END;
  inOpen := TRUE;
  (* tempor„res File ”ffnen *)
  IF ~mtTextfiles.OpenTextfile (tmpf, mtTextfiles.WRITE, 32000, out)
  THEN
    error ("Kann tempor„re Datei nicht anlegen!");
  END;
  outOpen := TRUE;
  (* Jetzt sind beide Dateien offen, also loslegen *)
  inNormalMessage := FALSE;
  WHILE ~mtTextfiles.EndofText (in) DO
    mtTextfiles.ReadLine (in, line);
    mtTextfiles.ReadLn (in);
    CASE line[0] OF
      'W',
      'N',
      'V'   : CheckHeadLine (line); |
      '#'   : inNormalMessage := CheckId (line); |
      ':'   : IF inNormalMessage
              THEN
                CheckTextLine (line); 
              END; |
    ELSE
    END;
    mtTextfiles.WriteLine (out, line);
    mtTextfiles.WriteLn (out);
  END;
  mtTextfiles.CloseTextfile (in);
  mtTextfiles.CloseTextfile (out);
  inOpen:= FALSE;
  outOpen := FALSE;
  (* Jetzt OUTFILE.TXT l”schen und tmp-Datei umbenennen *)
  IF ~MagicDOS.Fdelete (outf) THEN 
    error ("Kann OUTFILE.TXT nicht l”schen!");
  END;
  IF MagicDOS.Frename (tmpf, outf) # 0
  THEN
    error ("Kann OUTFILE.TMP nicht zu OUTFILE.TXT umbenennen!");
  END;
  InOut.WriteString ("ISO-Filterung erfolgreich durchgef�hrt.");
  InOut.WriteLn;
  InOut.WriteCard (headLinesChanged, 0);
  InOut.WriteString (" Headerzeilen ge„ndert und ");
  InOut.WriteCard (charsChanged,0);
  InOut.WriteString (" Zeichen umgesetzt.");
  InOut.WriteLn;
  MagicSys.Terminate (0);
END IsoFilt.
